import { Component, OnInit, ViewContainerRef, ViewChild, ElementRef, Renderer2 } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';

import FormatGeoJSON from 'ol/format/geojson';

import { NgxOlVisibleGraticule, ngxOlSelector } from '../../../ngx-ol/store';
import { foldingSelector, AutoLocateDistrict, SetUpload } from '../../store';
import { Folding } from '../../models';
import { SideComponentLoaderService } from '../../services';

import { ResourceTreeComponent, LayerAbstract } from '../../components';
import { SiderIsCollapsed, State } from '../../../store';

import * as fromFeatureSelectors from '../../store/selectors/feature.selector';
import { DrawToolDeactiveAll } from '../../store/actions/draw-tool.action';
import { Feature } from '../../models';

import { FeaturePropertyService, FeaturePropertyRef } from '../../components/feature-property';
import { PropertiesComponent } from '../../components/properties/properties.component';
import { InteractionSelectDeactive, InteractionSelectActive } from '../../store/actions/interaction-select.action';
import { NgxOlUploadOverlayRef, NgxOlUploadOverlayService, NgxOlUploadOverlayResult } from '../../../ngx-ol-upload-overlay';
import { Layer } from '../../class';
import { LayerTypes } from '../../enums';
import { LoadLayerSuccess } from '../../store/actions/layers.action';

@Component({
  selector: 'ege-map',
  templateUrl: './map.component.html',
  styleUrls: ['./map.component.scss']
})
export class MapComponent implements OnInit {

  @ViewChild('resourceTree', { read: ViewContainerRef }) viewContainerRef: ViewContainerRef;
  @ViewChild('featureProperty') featureProperty: ElementRef;
  @ViewChild('layoutTopRight') layoutTopRight: ElementRef;
  @ViewChild('layoutBottom') layoutBottom: ElementRef;

  resourceTreeVisible: boolean = false;
  mapGraticuleVisible$: Observable<boolean>;
  
  private uploadModal: NgxOlUploadOverlayRef;
 
  constructor(
    private store: Store<State>,
    private sideComponentLoader: SideComponentLoaderService,
    private renderer: Renderer2,
    private featurePropertyService: FeaturePropertyService,
    private ngxOlUploadOverlayService: NgxOlUploadOverlayService
  ) { }

  ngOnInit() {
    this.store.dispatch(new SiderIsCollapsed(true));
    this.store.dispatch(new AutoLocateDistrict());
    this.listenResourceTreeVisibleChange();
    this.graticuleVisible();
    this.listenFeatureSelected();
    this.store.select(foldingSelector.getFoldingSpaticlFiltering).subscribe((fold: Folding) => {
      if(fold) {
        if(fold.visible) {
          this.store.dispatch(new InteractionSelectDeactive());
        } else {
          this.store.dispatch(new InteractionSelectActive());
          this.store.dispatch(new DrawToolDeactiveAll());
        }
      }
    });
    this.store.select(foldingSelector.getFoldingUpload).subscribe((fold: Folding) => fold && this.openUploadModal(fold));
  }

  listenResourceTreeVisibleChange(): void {
    this.store.select(foldingSelector.getFoldingResourceTree).subscribe((resourceTree: Folding) => {
      if(resourceTree && resourceTree.visible) {
        this.renderer.addClass(this.layoutTopRight.nativeElement, 'has-resource-tree-position');
        this.renderer.addClass(this.layoutBottom.nativeElement, 'has-resource-tree-position');
      } else {
        this.renderer.removeClass(this.layoutTopRight.nativeElement, 'has-resource-tree-position');
        this.renderer.removeClass(this.layoutBottom.nativeElement, 'has-resource-tree-position');
      }
      if(resourceTree && resourceTree.visible && !this.resourceTreeVisible) {
        this.showResourceTree();
      }
    });
  }

  graticuleVisible(): void {
    this.store.select(foldingSelector.getFoldingGrid)
      .subscribe((gird: Folding) => {
        if(gird) {
          this.store.dispatch(new NgxOlVisibleGraticule(gird.visible));
        }
      });
    this.mapGraticuleVisible$ = this.store.select(ngxOlSelector.getNgxOlGraticuleVisible);
  }

  showResourceTree(): void {
    this.resourceTreeVisible = true;
    this.sideComponentLoader.show({
      viewContainerRef: this.viewContainerRef,
      component: ResourceTreeComponent,
      params: {
        a: 1
      }
    }).subscribe(() => {
      console.log('change');
    }, () => {
      this.resourceTreeVisible = false;
    }, () => {
      this.resourceTreeVisible = false;
    });
  }

  listenFeatureSelected(): void {
    let modeRf: FeaturePropertyRef;
    this.store.select(fromFeatureSelectors.getFeatureSelected)
      .subscribe((feature: Feature) => {
        modeRf && modeRf.close();
        if(feature) {
          modeRf = this.featurePropertyService.create(
            this.featureProperty.nativeElement, 
            {
              title: `${feature.layerName}`,
              component: PropertiesComponent,
              componentParams: feature
            }
          );
        }
      });
  }

  private randomLayerId(): string {
    const date = new Date();
    return `UPLOAD_ID_${date.valueOf()}-${Math.floor(Math.random() * 10000)}`;
  }

  /**
   * @private
   * @param options NgxOlUploadOverlayResult
   */
  private addLayerByUpload(options: NgxOlUploadOverlayResult): void {
    const format = new FormatGeoJSON();
    const geojson = format.writeFeatures(options.features);
    const layer: Layer = {
      id: this.randomLayerId(),
      title: options.layerName,
      type: LayerTypes.GEOJSON,
      options: null,
      geojson,
      mapViewable: true,
      tableViewable: true,
      visiable: options.visible,
      zoomTo: options.zoomTo
    };
    this.store.dispatch(new LoadLayerSuccess([layer]));
  }

  /**
   * @private
   * @param fold Folding
   */
  private openUploadModal(fold: Folding): void {
    if(fold.visible && !this.uploadModal) {
      this.uploadModal = this.ngxOlUploadOverlayService.open({
        title: '上传文件',
        width: '768px',
        maskClosable: false
      });
      this.uploadModal.afterClose.subscribe((result: NgxOlUploadOverlayResult) => {
        result && this.addLayerByUpload(result);
        this.store.dispatch(new SetUpload({ ...fold, visible: false }));
      });
    } else {
      this.uploadModal && this.uploadModal.destroy();
      this.uploadModal = null;
    }
  }

}
